-- DemonStatueM
-- Create by panyl
-- 魔神雕像

module("DemonStatueM", package.seeall);

-- 所有的雕像配置信息
local demonStatues = {};
local demonMap     = {};

-- 正统的迷宫
local regularDungeon = 9;           -- 血腥要塞

local whenRefreshProp;
local whenStartFloor;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    demonStatues = {};
    demonMap     = {};

    -- 转换下demon_statue信息表
    local demon_statue_CSV = get_demon_statue_CSV();
    for i = 1, #demon_statue_CSV do
        local row = demon_statue_CSV[i];
        demonStatues[row.id] = row;

        local class = row.classify;
        demonMap[class] = demonMap[class] or {};

        demonMap[class][row.level] = row;
    end
end

-- 模块初始化
function init()
    loadCsv();

    -- 注册刷新属性回调
    PropM.registerRefreshCallback("DemonStatueM", whenRefreshProp);

    EventMgr.removeAll("DemonStatueM");
    -- 离开迷宫回调
    EventMgr.register("DemonStatueM", event.LEAVE_DUNGEON, function()
        -- 删除当前exp值
        ME.user.dbase:delete("demon_exp");
        ME.user.dbase:delete("statue_appear");
    end);

    -- 迷宫准备好
    EventMgr.register("DemonStatueM", event.DUNGEON_AREADY, whenStartFloor);
end

-- 开始迷宫
whenStartFloor = function()
    -- 如果不是第一层
    if DungeonM.currentLayer() ~= 1 then
        return;
    end

    local props = PropM.fetchProps(ME.user, "demon_statue");
    for _, prop in ipairs(props) do
        PropM.trigger(ME.user, prop[1], prop[2]);
    end
end

whenRefreshProp = function(who)
    -- 如果不是玩家
    if who.type ~= OBJECT_TYPE_USER then
        return;
    end

    -- 先清除属性
    who.dbase:deleteTemp("prop", "demon_statue");

    -- 如果不在迷宫中了
    if not DungeonM.isInDungeon() then
        return;
    end

    local demonExp = who.dbase:query("demon_exp");
    if not demonExp then
        return;
    end

    for class, exp in pairs(demonExp) do
        local data = demonMap[class];
        for level = 1, #data do
            if data[level]["exp"] > exp then
                break;
            end

            -- 附加属性
            applyDemonProp(who, data[level]["id"]);
        end
    end
end

-- 附加魔神属性
function applyDemonProp(who, id)
    local info = calcDemonBonus(who, id);
    local props = info["prop"];

    if not props or #props <= 0 then
        return;
    end

    if type(props[1]) ~= "table" then
        props = { props };
    end

    for _, prop in pairs(props) do
        PropM.record(who, prop, "demon_statue");
    end
end

-- 计算魔神雕像的奖励
function calcDemonBonus(who, id)
    local path = "bonus";

    -- 如果不是在正统迷宫中
    local dungeonId = ME.user.dbase:query("current_dungeon") or DungeonM.getDungeonId();
    if not isRegularDungeon(dungeonId) then
        path = "other_bonus";
    end

    -- 配置的
    return query(id, path);
end

-- 检索
function query(classId, path)
    local m = demonStatues[classId];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 根据类型检索
function queryStatue(class, level)
    local m = demonMap[class];

    if not m or not level then
        return m;
    end

    return m[level];
end

-- 获取雕像奖励描述
function getStatueBonusDesc(class, level)
    local m = queryStatue(class, level);

    if not m then
        return;
    end

    local path = "desc";

    -- 如果是在非正统迷宫中
    local dungeonId = DungeonM.getDungeonId();
    if not isRegularDungeon(dungeonId) then
        path = "other_desc";
    end

    return m[path];
end

-- 所有类型
function getAllStatue()
    return table.keys(demonMap);
end

-- 是否正统的迷宫
function isRegularDungeon(dungeonId)
    return DungeonAreaM.getParentId(dungeonId) == regularDungeon;
end

-- 判断某雕像是否已经满级了
function isTopLevel(class)
    local demonExp = ME.user.dbase:query("demon_exp", {});
    local curExp   = demonExp[class] or 0;
    local maxLevel = #table.keys(demonMap[class]);

    return curExp >= demonMap[class][maxLevel]["exp"];
end

-- 初始化魔神雕像
function initStatueData()
    -- 如果不是血腥要塞中
    local dungeonId = DungeonM.getDungeonId();
    if not isRegularDungeon(dungeonId) then
        local props = PropM.fetchProps(ME.user, "demon_statue");
        if #props > 0 then
            return {["classify"] = props[1][2], };
        end
    end

    local normalList = {};
    local priorityList = {};
    local appearRecord = ME.user.dbase:query("statue_appear", {});
    local curLayer = DungeonM.currentLayer();

    for class, _ in pairs(demonMap) do
        repeat
            -- 如果已经满级了，忽略
            if isTopLevel(class) then
                break;
            end

            -- 如果已经有10层没有出现了
            if not appearRecord[class] or
                appearRecord[class] + 10 <= curLayer then
                table.insert(priorityList, class);
            else
                table.insert(normalList, class);
            end
        until true;
    end

    -- 排序
    table.sort(priorityList);
    table.sort(normalList);

    local rand = DungeonM.getRandSeed("demon_statue");

    local class;
    -- 优先
    if #priorityList > 0 then
        class = priorityList[rand % #priorityList + 1];
    elseif #normalList > 0 then
        class = normalList[rand % #normalList + 1];
    end

    if not class then
        return {};
    end

    appearRecord[class] = curLayer;
    ME.user.dbase:set("statue_appear", appearRecord);

    return {["classify"] = class, };
end

-- 获取信息(当前等级、历史最高等级)
function getDemonInfo(class)
    local demonExp    = ME.user.dbase:query("demon_exp", {});
    local demonStatue = ME.user.dbase:query("demon_statue", {});
    local curExp = demonExp[class] or 0;
    local maxLevel = demonStatue[class] or 0;
    local data = demonMap[class];
    local ret = {
        ["max_level"] = maxLevel,
        ["cur_level"] = 0,
        ["exp"]       = curExp,
    };

    for level = 1, #data do
        if data[level]["exp"] <= curExp then
            ret["cur_level"] = level;
        else
            break;
        end
    end

    return ret;
end

-- 计算单件装备的exp
function calcEquipExp(classId)
    -- local dbase = EquipM.query(classId, "dbase") or {};

    -- return dbase["demon_exp"] or 0;

    return FormulaM.invoke("CALC_DEMON_STATUE_EQUIP_EXP", classId);
end

-- 计算套装的额外exp
function calcSuitExp(suitId)
    -- local dbase = SuitM.query(suitId, "dbase") or {};

    -- return dbase["demon_exp"] or 0;
    local ret = 0;
    for _, classId in pairs(SuitM.query(suitId, "active")) do
        ret = ret + calcEquipExp(classId);
    end

    return ret + FormulaM.invoke("CALC_DEMON_STATUE_SUIT_EXP", suitId);
end

-- 计算总共的exp
function calcTotalExp(equips)
    -- 分离出套装和普通装备
    local m = suitFilter(equips);
    local exp = 0;

    -- 先提交单件
    for _, classId in pairs(m["normal"]) do
        exp = exp + calcEquipExp(classId);
    end

    -- TODO: 接下来提交套装
    for _, suitId in pairs(m["suit"]) do
        exp = exp + calcSuitExp(suitId);
    end

    return exp;
end

-- 判断能否提交意见装备
function canSubmit(classId)
    -- 是否装备
    if not EquipM.isEquipment(classId) then
        return false;
    end

    -- 是否是神器
    if ArtifactM.isArtifact(classId) then
        return false;
    end

    -- 如果没有此装备
    if ItemM.getAmount(ME.user, classId) <= 0 then
        return false;
    end

    -- 该类装备没有exp值
    if calcEquipExp(classId) <= 0 then
        return false;
    end

    return true;
end

-- 提交装备
function submit(equips, pos)
    local grid = DungeonM.getGridByPos(pos);

    -- 如果格子不是
    if grid.type ~= GRID_TYPE_DEMON_STATUE then
        cclog("格子类型不对")
        return false;
    end

    -- 遍历所有的装备
    local m = {};
    for _, classId in pairs(equips) do
        if not canSubmit(classId) then
            cclog(string.format("装备%d不能提交", classId));
            return false;
        end

        m[classId] = (m[classId] or 0) + 1;
        if ItemM.getAmount(ME.user, classId) < m[classId] then
            return false;
        end
    end

    -- 分离出套装和普通装备
    local m = suitFilter(equips);

    -- 先提交单件
    for _, classId in pairs(m["normal"]) do
        submitEquip(classId, pos);
    end

    -- TODO: 接下来提交套装
    for _, suitId in pairs(m["suit"]) do
        submitSuit(suitId, pos);
    end

    -- 增加exp
    local demonExp = calcTotalExp(equips);
    local upgradeLevel, bonusList = tryUpgrade(demonExp, grid.classify);

    -- 抛出献祭事件
    EventMgr.fire(event.DEMON_SUBMIT, {
        ["isUpgrade"] = upgradeLevel > 0,
        ["classify"] = grid.classify,
        ["upgradeLevel"] = upgradeLevel,
        ["bonusList"] = bonusList,
        ["pos"] = pos, });

    -- 邪神信仰专属发动特效
    local prop = PropM.combine(ME.user, "demon_statue", "demigod_lich");
    if prop[3] > 0 and grid.classify == "demigod_lich" then
        -- 触发特技发动事件
        EventMgr.fire(event.SPECIAL_SKILL_TRIGGER, { propId = prop[1] });
    end

    -- action已经添加上去了
    return true, true;
end

-- 过滤出套装
function suitFilter(equips)
    -- TODO: 需要把套装提取出来
    local normalEquips = {};
    local suits = {};
    local filter = {};
    local total = #equips;
    for i = 1, total do
        local classId = equips[i];
        local suitId  = EquipM.query(classId, "suit");
        local tempFilter = { [i] = true, };
        local suitMap    = { [classId] = true, };

        -- 未筛掉的套装
        if type(suitId) == "number" and suitId > 0 and not filter[i] then
            -- 往后面找，凑套装
            for j = i + 1, total do
                local classId2 = equips[j];
                local suitId2 = EquipM.query(classId2, "suit");

                -- 同样是未筛掉的同一套套装
                if suitId2 == suitId and
                    not filter[j] and
                    not suitMap[classId2] then
                    tempFilter[j] = true;
                    suitMap[classId2] = true;
                end
            end

            -- 不管有没有凑够整套，都需要筛掉
            filter = table.add(filter, tempFilter);

            local arr = table.keys(suitMap);
            if #SuitM.query(suitId, "active") == #arr then
                -- 凑够了一套
                table.insert(suits, suitId);
            else
                -- 没有凑够一套
                normalEquips = table.append(normalEquips, arr);
            end
        elseif not filter[i] then
            -- 普通装备
            table.insert(normalEquips, classId);
        end
    end

    return {["suit"] = suits, ["normal"] = normalEquips, };
end

-- 提交套装
function submitSuit(suitId, pos)
    local grid = DungeonM.getGridByPos(pos);

    -- 该套装所有的装备
    local equips = SuitM.query(suitId, "active") or {};
    if #equips <= 0 then
        return false;
    end

    -- 扣除装备
    for _, classId in pairs(equips) do
        ItemM.costAmount(ME.user, classId, 1);
    end

    local data = suitId * 2 + 0;
    DungeonM.addAction({["cmd"] = "sacrifice_demon", ["pos"] = pos, ["data"] = data, });
    return true;
end

-- 提交单件装备
function submitEquip(classId, pos)
    local grid = DungeonM.getGridByPos(pos);

    -- 扣除一件装备
    ItemM.costAmount(ME.user, classId, 1);

    local data = classId * 2 + 1;
    DungeonM.addAction({["cmd"] = "sacrifice_demon", ["pos"] = pos, ["data"] = data, });
    return true;
end

-- 尝试升级
function tryUpgrade(exp, class)
    local demonExp = ME.user.dbase:query("demon_exp", {});
    local demonStatue = ME.user.dbase:query("demon_statue", {});
    ME.user.dbase:set("demon_exp", demonExp);
    ME.user.dbase:set("demon_statue", demonStatue);

    -- 当前exp
    local curExp = demonExp[class] or 0;
    local nextExp = curExp + exp;
    local curLevel = 0;
    local data = demonMap[class];

    local upgradeLevel = 0;
    local bonusList = {};

    -- 先修改当前的exp
    demonExp[class] = nextExp;

    -- 奖励
    for level = 1, #data do

        BonusM.clearBonusCollect();
        BonusM.startBonusCollect();

        local requireExp = data[level]["exp"];

        if requireExp > curExp and requireExp <= nextExp then
            -- 奖励
            doBonus(data[level]["id"]);

            -- 魔神雕像属性
            applyDemonProp(ME.user, data[level]["id"]);

            -- 等级
            curLevel = level;

            BonusM.endBonusCollect();
            local bonus = BonusM.getBonusCollect();

            BonusM.clearBonusCollect();

            upgradeLevel = upgradeLevel + 1;
            table.insert(bonusList, bonus);
        elseif requireExp > nextExp then
            -- 超出的部分就不用管了
            break;
        end
    end

    BonusM.endBonusCollect();
    BonusM.clearBonusCollect();

    -- 曾经达到的最高等级
    local everLevel = demonStatue[class] or 0;
    demonStatue[class] = math.max(everLevel, curLevel);

    -- 抛出事件
    EventMgr.fire(event.DEMON_STATUE_UPGRADE, {
        ["class"] = class,
        ["level"] = curLevel,});

    return upgradeLevel, bonusList;
end

-- 奖励
function doBonus(id)
    local info = calcDemonBonus(ME.user, id);
    local keys = table.keys(info);
    table.sort(keys);

    for i = 1, #keys do
        local key = keys[i];
        local value = info[key];

        if key == "bonus" then
            local arr = value;
            if type(arr[1]) ~= "table" then
                arr = { value, };
            end

            for _, bonus in pairs(arr) do
                BonusM.doBonus(bonus, "demon_bonus");
            end
        end
    end
end
